package work.linruchang.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.BasicType;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.TypeUtil;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.util.*;

/**
 * @author LinRuChang
 * @version 1.0
 * @date 2022/10/09
 * @since 1.8
 **/
public class EnhanceClassUtil extends ClassUtil {


    /**
     * 获取数组元素的反射，非数组直接返回null
     * @param arrayClazz 数组Class
     * @return
     */
    public static Class getArrayElementClass(Class arrayClazz) {
        if(arrayClazz != null && arrayClazz.isArray()) {
            return forName(StrUtil.removeAny(arrayClazz.getName(),"[L", ";"));
        }
        return null;
    }

    /**
     * 某字段的类型是容器，获取其容器的元素类型
     * <p>
     * List<Long>  ==> Long.class
     * List ==> Object.class
     *
     * @param field
     * @return
     */
    public static Class getCollElemType(Field field) {
        Assert.notNull(field, "缺乏字段，请检查");
        Assert.isTrue(Collection.class.isAssignableFrom(field.getType()), "入参必须是容器类型的字段，请检查：{}", field);
        Type genericType = field.getGenericType();
        if (ParameterizedType.class.isAssignableFrom(genericType.getClass())) {
            return (Class) TypeUtil.getTypeArgument(genericType);
        } else {
            return Object.class;
        }
    }

    public static boolean isNumberType(Class clazz) {
        boolean result = false;
        if (clazz != null) {
            List<? extends Class<? extends Number>> numberClasses = Arrays.asList(Byte.class, Byte.TYPE, Short.class, Short.TYPE, Integer.class, Integer.TYPE, Long.class, Long.TYPE, BigInteger.class, Float.class, Float.TYPE, Double.class,Double.TYPE);
            if (CollUtil.contains(numberClasses, clazz)) {
                result = true;
            } else {
                // TODO
            }
        }
        return result;
    }

    public static boolean isDateType(Class clazz) {
        boolean result = false;
        if (clazz != null) {
            List<Class> dateClasses = Arrays.asList(Date.class, Calendar.class, LocalDate.class, LocalDateTime.class, ZonedDateTime.class,java.sql.Date.class);
            if (CollUtil.contains(dateClasses, clazz)) {
                result = true;
            } else {
                // TODO
            }
        }
        return result;
    }


    /**
     * 获取基本变量类型,找不到直接返回null
     * @param type 基本变量类型全限定名
     * @return
     */
    public static Class getBasicType(String type) {
        return BasicType.WRAPPER_PRIMITIVE_MAP.values().stream()
                .filter(clazz -> StrUtil.equals(type, clazz.getName()))
                .findFirst()
                .orElse(null);
    }

    /**
     * 获取类型，找不到不抛异常直接返回null
     *
     * 支持基本类型反射获取
     * @param type 类型的全限定名
     * @return
     */
    public static Class getType(String type) {
        return ObjectUtil.defaultIfNull(forName(type), getBasicType(type));
    }

    /**
     * 获取所有父类，不含Object.class
     * @param clazz 反射
     * @return
     */
    public static List<Class> superClasses(Class clazz) {
        List<Class> result = CollUtil.newArrayList();
        if (clazz != null) {
            while (true) {
                clazz = clazz.getSuperclass();
                if (clazz == Object.class) {
                    break;
                }
                result.add(clazz);
            }
        }
        return result;
    }

    /**
     * 获取JDK类型，如果类型非jdk,直接返回null
     *
     * @param type 类型全限定名
     * @return
     */
    public static Class getJdkClass(String type) {
        Class result = getBasicType(type);
        if (result == null) {
            result = forName(type);
            result = isJdkClass2(result) ? result : null;
        }
        return result;
    }

    /**
     * 是否是JDK定义的类型
     * @param clazz
     * @return
     */
    public static boolean isJdkClass2(Class clazz) {
        if (clazz == null) {
            return false;
        }
        boolean javaFlag = StrUtil.startWithAny(clazz.getName(), "java.", "[Ljava.");
        if (!javaFlag) {
            return superClasses(clazz).stream()
                    .anyMatch(superClazz -> StrUtil.startWithAny(superClazz.getName(), "java.", "[Ljava."));
        }
        return javaFlag;
    }

    /**
     * 获取Class实例 == 获取不到不会抛出异常
     * @param type 类全限定名
     * @return
     */
    public static Class forName(String type) {
        try {
            return Class.forName(type);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 是否【是】普通字段的类型
     * @param type 类型全限定名
     * @return
     */
    public static boolean isBeanFieldJavaType(String type) {
        return getJdkClass(type) != null;
    }

    /**
     * 是否【不是】普通字段的类型
     * @param type 类型全限定名
     * @return
     */
    public static boolean isNotBeanFieldJavaType(String type) {
        return !isBeanFieldJavaType(type);
    }
}
